package com.dyb.demo.test_thread.thread;

import com.dyb.demo.util.PrintUtils;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * wait() 需要结合synchronized 使用
 * Lock 和 Condition 结合使用，实现线程通信
 *
 * ！！！ wait/notify调用前必须先获取对象锁，必须作用于同一个锁对象
 * 在调用await(),signal(),signalAll()等方法的时候,也必须要获得锁,
 * 也就是必须在 lock.lock()和lock.unlock()代码块儿之间才能调用这些方法,否则就会抛出IllegalMonitorStateException
 */
public class TestWait {

    public static void main(String[] args) {
        Test testWait = new Test();

         ThreadFactory namedThreadFactory = Executors.defaultThreadFactory();
        /*ThreadFactory factory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "thread-name");
            }
        };*/

        // ThreadFactory namedThreadFactory = (r -> new Thread(r, "demo-pool-" + r.hashCode()));
        ExecutorService singleThreadPool = new ThreadPoolExecutor(2, 2,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(16), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

        CountDownLatch countDownLatch = new CountDownLatch(2);

        singleThreadPool.execute(() -> {
            testWait.method1();
            countDownLatch.countDown();
        });
        singleThreadPool.execute(() -> {
            testWait.method2();
            countDownLatch.countDown();
        });

        testWait.notifyMethod();
        testWait.signalMethod();

        try {
            countDownLatch.await();
            PrintUtils.printWithThreadName("线程池任务执行完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        singleThreadPool.shutdown();
    }
}

class Test {

    private final AtomicInteger integer = new AtomicInteger(1);

    /**
     * object.wait()
     * @author dyb
     * @date 2020/7/18
     */
    void method1() {
        synchronized(integer) {
            try {
                PrintUtils.printWithThreadName("start m1");
                // 释放锁对象
                integer.wait();
                PrintUtils.printWithThreadName("end m1");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 唤醒object.wait()
     */
    void notifyMethod() {
        try {
            // 睡眠确保wait()执行
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized(integer) {
            PrintUtils.printWithThreadName("唤醒object.wait");
            integer.notify();
        }

    }

    private final ReentrantLock lock = new ReentrantLock();
    /**
     * lock.newCondition() 每次都会创建新的对象
     */
    private final Condition condition = lock.newCondition();

    /**
     * lock.wait()
     * @author dyb
     * @date 2020/7/18
     */
    void method2() {
        lock.lock();
        try {
            PrintUtils.printWithThreadName("start m2");
            // 释放锁
            condition.await();
            PrintUtils.printWithThreadName("end m2");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 唤醒lock.wait()
     */
    void signalMethod() {
        try {
            // 睡眠确保wait()执行
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.lock();
        try {
            PrintUtils.printWithThreadName("唤醒lock.wait");
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}